package com.tengju.user.application.user;

import com.tengju.user.domain.annotation.Sensitive;
import com.tengju.user.domain.model.user.SsoUserId;
import com.tengju.user.domain.model.user.StaffId;
import com.tengju.user.domain.service.BrandPermissionExternalService;
import com.tengju.user.domain.shared.SensitiveFieldType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 用户数据权限
 *
 * @Author: 李大仙
 * @Date: 2021/4/9 5:48 下午
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class UserDataAuthService {

    private final BrandPermissionExternalService brandPermissionExternalService;

    @Value("${sso.data.permission.code}")
    private String dataPermissionCode;

    /**
     * 敏感数据处理
     *
     * @param list    敏感数据集合
     * @param staffId 用户id（sso id）
     * @return 数据集合
     */
    public <T> List<T> dataMasking(List<T> list, StaffId staffId) {
        //1、先判断list是否为空，是否有查询结果记录
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }
        //2、获得该用户角色
        List<String> dataPermissionList = brandPermissionExternalService.getDataPermission(new SsoUserId(staffId.getValue()));
        //3、对查询结果脱敏
        return dataMasking(list, dataPermissionList, staffId.getValue());
    }

    /**
     * 通过反射获取带注解的值,然后去做脱敏
     *
     * @param objectList         需要脱敏的对象
     * @param dataPermissionList 数据权限code列表
     * @return 返回处理后的对象
     */
    private <T> List<T> dataMasking(List<T> objectList, List<String> dataPermissionList, Long ssoUserId) {
        //list为空,直接返回
        if (CollectionUtils.isEmpty(objectList)) {
            return objectList;
        }
        for (T object : objectList) {
            // 首先通过反射获取object对象的类有哪些字段
            Field[] fields = object.getClass().getDeclaredFields();
            // for循环逐个字段校验，看哪个字段上标了注解
            for (Field field : fields) {
                // if判断：检查该字段上有没有标注了@RoleDesensit注解
                if (field.isAnnotationPresent(Sensitive.class)) {
                    // 通过反射获取到该字段上标注的@RoleDesensit注解的详细信息
                    Sensitive sensitive = field.getAnnotation(Sensitive.class);
                    SensitiveFieldType type = sensitive.type();
                    // 让我们在反射时能访问到私有变量
                    field.setAccessible(true);
                    String value;
                    try {
                        // 用过反射获取字段的实际值
                        value = ((String) field.get(object));
                        //拿着value，角色roleList,脱敏类型去做脱敏
                        field.set(object, masking(value, dataPermissionList, type, ssoUserId));
                    } catch (Exception e) {
                        log.error("error ", e);
                    }
                }
            }
        }
        return objectList;
    }

    private String masking(String value, List<String> dataPermissionList, SensitiveFieldType type, Long ssoUserId) {
        if (StringUtils.isBlank(value)) {
            return value;
        }
        if (dataPermissionList.contains(dataPermissionCode)) {
            log.info("[公共脱敏处理][该用户拥有敏感数据权限,正在查看信息字段类型：{}][该用户ssoUserId:{}]", type, ssoUserId);
            return value;
        }
        if (dataPermissionList.contains(type.getType())) {
            log.info("[公共脱敏处理][该用户拥有敏感数据权限,正在查看信息字段类型：{}][该用户ssoUserId:{}]", type, ssoUserId);
            return value;
        }
        //没有则根据公共规则脱敏
        try {
            value = type.dealData(value);
        } catch (Exception e) {
            log.error("[公共脱敏处理][脱敏失败,有异常抛出]原脱敏值:{},脱敏类型:{},失败原因:" + value, type, e);
        }
        return value;
    }

//    /**
//     * 公共脱敏方法
//     *
//     * @param value 需要脱敏的值
//     * @param type  脱敏类型
//     * @return 返回脱敏后的字符串
//     */
//    private String dealData(String value, SensitiveFieldType type) {
//        //判断长度是否为2，若为2则认为是姓名，只脱最后一位
//        if (SensitiveFieldType.NAME.equals(type)) {
//            if (value.length() > 2) {
//                return StringUtils.left(value, 1).concat(StringUtils.leftPad(StringUtils.right(value, 1), StringUtils.length(value) - 1, "*"));
//            }
//            return value.charAt(0) + "*";
//        } else if (SensitiveFieldType.MOBILE.equals(type) || SensitiveFieldType.IDENTITY_NO.equals(type)) {
//            if (value.startsWith("+")) {
//                return StringUtils.left(value, 5).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 5, "*"));
//            }
//            //国外手机号
//            return StringUtils.left(value, 3).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 3, "*"));
//        } else if (SensitiveFieldType.BANKCARD_NO.equals(type)) {
//            //银行卡号处理
//            return StringUtils.left(value, 6).concat(StringUtils.leftPad(StringUtils.right(value, 4), StringUtils.length(value) - 6, "*"));
//        } else if (SensitiveFieldType.COMPANY_ADDRESS.equals(type)) {
//            //公司地址处理
//            return StringUtils.rightPad(StringUtils.left(value, 3), StringUtils.length(value), "*");
//        } else if (SensitiveFieldType.DUTY_PARAGRAPH.equals(type)) {
//            //税号处理
//            return "****";
//        }
//        return value;
//    }
}
